/*
* Created on 02-Jul-2006
*
* Copyright (c) 2006 P.J.Leonard
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* Frinika is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.benchmark;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
public class OutputBufferTest implements Runnable {
Mixer.Info currentMixer;
AudioFormat format = new AudioFormat(44100.0f, 16, 2, true, true);
DataLine.Info infoOut = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine lineOut;
boolean isRunning = false;
boolean hasStopped = false;
// 512 frames by default
int bufferSize = 2048;
/**
* Ultra low latency mode can be used for small buffer sizes to obtain
* better latency - BUT it eats all your CPU.
*/
protected boolean ultraLowLatency = false;
/**
* Use Java standard way of latency control (blocking on sdl.write)
*/
protected boolean standardLatency = false;
/**
* Use Frinika estimated frame pos (using System.nanoTime) or
* SDL.getLongFramePosition
*/
private boolean useEstimatedFramePos = true;
public OutputBufferTest(int bufferSize) {
if (System.getProperty("os.name").equals("Mac OS X")) {
System.out
.println("Detected Mac OS X. Automatically tuning audio device settings. ");
// These are the settings working best on a G5 iMac 2Ghz
useEstimatedFramePos = false;
ultraLowLatency = true;
}
currentMixer = AudioSystem.getMixerInfo()[0];
this.bufferSize = 4 * bufferSize;
startAudioOutput();
}
public void startAudioOutput() {
try {
lineOut = (SourceDataLine) AudioSystem.getMixer(currentMixer)
.getLine(infoOut);
if (standardLatency)
lineOut.open(format, bufferSize);
else
lineOut.open(format);
lineOut.start();
System.out.println("Buffersize: " + bufferSize + " / "
+ lineOut.getBufferSize());
} catch (Exception e) {
lineOut = null;
System.out
.println("No audio output available. Use Audio Devices dialog to reconfigure.");
}
Thread thread = new Thread(this);
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
}
public void stopAudioOutput() throws Exception {
isRunning = false;
while (!hasStopped)
Thread.yield();
hasStopped = false;
if (lineOut != null) {
lineOut.drain();
lineOut.stop();
lineOut.close();
}
}
public void run() {
try {
isRunning = true;
byte[] outBuffer = new byte[bufferSize];
float[] floatBuffer = new float[bufferSize / 2];
long totalTimeNanos = (long) ((bufferSize / 4f) / (44100.f * 1000000000f));
// nanoTime when buffer expires
long expireNanos = 0;
long framesWritten = 0;
while (isRunning) {
long startTimeNanos = System.nanoTime();
for (int n = 0; n < (floatBuffer.length); n++)
floatBuffer[n] = 0;
long endTimeNanos = System.nanoTime();
if (lineOut != null) {
System.out.println(lineOut.getBufferSize()
- lineOut.available());
lineOut.write(outBuffer, 0, outBuffer.length);
}
if (expireNanos < System.nanoTime())
expireNanos = System.nanoTime() + totalTimeNanos;
else
expireNanos += totalTimeNanos;
long sleepNanos = expireNanos - totalTimeNanos
- System.nanoTime();
if (sleepNanos > 0)
Thread.sleep(sleepNanos / 1000000,
(int) (sleepNanos % 1000000));
}
// This is used when not using the Frinika estimated position
framesWritten += (outBuffer.length / 4);
// cpuMeter.setCpuPercent((int)(((float)(endTimeNanos -
// startTimeNanos) / (float)totalTimeNanos) * 100));
} catch (Exception e) {
e.printStackTrace();
}
hasStopped = true;
}
public void setBufferSize(int len) throws Exception {
stopAudioOutput();
bufferSize = len * 4;
startAudioOutput();
}
}